package com.mc.lp.database.dao.impl;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.LockMode;
import org.hibernate.ObjectDeletedException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.WrongClassException;
import org.hibernate.criterion.Criterion;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate4.HibernateJdbcException;
import org.springframework.orm.hibernate4.HibernateObjectRetrievalFailureException;
import org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException;
import org.springframework.orm.hibernate4.HibernateQueryException;
import org.springframework.orm.hibernate4.HibernateSystemException;
import org.springframework.stereotype.Repository;

import com.mc.lp.database.dao.IGenericCacheDAO;

/*
 * @author aphanda
 * @date Oct 13, 2014
 * @time 12:53:02 AM
 */

@Repository
public class GenericCacheDAOImpl<T> implements IGenericCacheDAO<T> {


	@Resource
	SessionFactory sessionFactory;

	private Class<T> clazz;

	protected final Session getCurrentSession() {
		return this.sessionFactory.getCurrentSession();
	}

	public void setClazz(final Class<T> clazzToSet) {
		this.clazz = clazzToSet;
	}

	@SuppressWarnings("unchecked")
	public List<T> findAll(Class<T> clazz1) throws DataAccessException {
		clazz = clazz1;
		
		return findByCriteria();
	}

	/**
	 * Use this inside subclasses as a convenience method.
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(Criterion... criterion) throws DataAccessException {

		try {

			Criteria crit = this.getCurrentSession().createCriteria(this.clazz);

			for (Criterion c : criterion) {

				crit.add(c);
			}
			crit.setCacheable(true);
			crit.setLockMode(LockMode.READ);

			return crit.list();
		} catch (ObjectNotFoundException e) {
			throw new HibernateObjectRetrievalFailureException(e);
		} catch (ObjectDeletedException e) {
			throw new HibernateObjectRetrievalFailureException(e);
		} catch (UnresolvableObjectException e) {
			throw new HibernateObjectRetrievalFailureException(e);
		} catch (WrongClassException e) {
			throw new HibernateObjectRetrievalFailureException(e);
		} catch (StaleObjectStateException e) {
			throw new HibernateOptimisticLockingFailureException(e);
		} catch (StaleStateException e) {
			throw new HibernateOptimisticLockingFailureException(e);
		} catch (JDBCException e) {
			throw new HibernateJdbcException(e);
		} catch (QueryException e) {
			throw new HibernateQueryException(e);
		} catch (HibernateException e) {
			throw new HibernateSystemException(e);
		}
	}

}
